﻿using Gma.System.MouseKeyHook;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.UI.WebControls;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.CompilerServices.RuntimeHelpers;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using System.IO;
using System.Reflection;
using Loamen.KeyMouseHook;
using Loamen.KeyMouseHook.Native;


namespace WinScanInputSimulate
{
    public partial class FormMain : Form
    {
        [DllImport("user32.dll")]
        static extern short VkKeyScan(char ch);

        [DllImport("user32.dll")]
        public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
        [DllImport("user32.dll")]
        private static extern bool IsIconic(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        [DllImport("user32.dll")]
        private static extern bool SetCursorPos(int X, int Y);
        [DllImport("user32.dll")]
        private static extern void mouse_event(uint dwFlags, int dx, int dy, int cButtons, uint dwData);

        // SW_SHOWMAXIMIZED宏定义，用于检查窗口是否最大化
        private const int SW_SHOWMAXIMIZED = 3;

        private const uint MOUSEEVENTF_LEFTDOWN = 0x02; // 鼠标左键按下
        private const uint MOUSEEVENTF_LEFTUP = 0x04;   // 鼠标左键抬起


        private readonly KeyMouseFactory eventHookFactory = new KeyMouseFactory(Hook.GlobalEvents());
        private readonly MouseWatcher mouseWatcher;

        PlcTcpIpHelper tcpIpHelper;
        Thread thread;

        #region 属性变量

        // 模拟鼠标点击的坐标
        int _mouseClickX = 100; // X坐标
        int _mouseClickY = 200; // Y坐标

        //最小化托盘
        private NotifyIcon notifyIcon;

        private const string SECTIONKEY = "base";
        private const string PARAMFILENAME = "param.ini";

        private string paramFile;

        private string serviceIp;
        private int port;
        private string softwareName;

        private int ThreadSleep = 2000;
        private int TextEntrySleep = 500;
        private int ShowItemCount = 200;
        private int TotalItemCount = 0;

        private InputSimulator sim = new InputSimulator();
        private AsyncTcpClient scanCameraClient;

        private int IsMinToNotifyIcon;
        private bool isStart = false;
        private bool isDebug = false;

        //条码写入到指定目录下，如果没有目录则输入到焦点下
        private string WriteFilePath = string.Empty;
        private bool isWirteFile;
        private bool IsFocusInput;
        private bool IsStartProcesses;
        private bool IsSpecifyFocusProcess;//是否明确指定焦点输入软件

        /// <summary>
        /// 要启动的进程名称，可以在任务管理器里查看，一般是不带.exe后缀的;
        /// </summary>
        private string _activateProcessesName;
        private string _startProcessesName;

        bool IsAutoRun;

        #endregion

        public FormMain()
        {
            InitializeComponent();

            paramFile = Thread.GetDomain().BaseDirectory + PARAMFILENAME;

            softwareName = GetInIValStr("softwareName");
            serviceIp = GetInIValStr("ServiceIp");
            port = GetInIValInt("ServicePort");
            ShowItemCount = GetInIValInt("ShowItemCount");

            IsMinToNotifyIcon = GetInIValInt("IsMinToNotifyIcon");

            ThreadSleep = GetInIValInt("ThreadSleepInput");
            if (ThreadSleep < 900)
            {
                ThreadSleep = 1000;
            }
            TextEntrySleep = GetInIValInt("TextEntrySleep");

            panel2.Visible = GetInIValStr("IpPortVisible") == "1" ? true : false;
            isDebug = GetInIValStr("isDebug") == "1" ? true : false;
            pnlTest.Visible = GetInIValStr("pnlTestShow") == "1" ? true : false;

            IsAutoRun = GetInIValStr("IsAutoRun") == "1" ? true : false;

            string version = "";// typeof(FormMain).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
            string buildTime = "";//File.GetLastWriteTime(typeof(FormMain).GetTypeInfo().Assembly.Location).ToString("yyyy-MM-dd HH:mm:ss");

            this.Text = softwareName;

            lblverbuildtime.Text = $"V{version} - {buildTime}";
            if (GetInIValStr("IsShowVerBuildTime") != "1")
            {
                lblverbuildtime.Visible = false;
            }

            // 初始化托盘图标
            if (IsMinToNotifyIcon > 0)
            {
                notifyIcon = new NotifyIcon();
                notifyIcon.Icon = this.Icon; // 使用窗体图标或者指定一个图标
                notifyIcon.Visible = false;
                notifyIcon.Click += new EventHandler(NotifyIcon_Click);
            }


            this.TopMost = GetInIValInt("IsTopMost") > 0 ? true : false;
            this.MinimizeBox = GetInIValInt("IsMinimizeBox") > 0 ? true : false;

            isWirteFile = GetInIValInt("IsCreateNcFile") > 0 ? true : false;
            IsFocusInput = GetInIValInt("IsFocusInput") > 0 ? true : false;
            IsStartProcesses = GetInIValInt("IsStartProcesses") > 0 ? true : false;
            IsSpecifyFocusProcess = GetInIValInt("IsSpecifyFocusProcess") > 0 ? true : false;

            WriteFilePath = GetInIValStr("WriteFilePath");
            _activateProcessesName = GetInIValStr("ActivateProcessesName");
            _startProcessesName = GetInIValStr("StartProcesses");
            _mouseClickX = GetInIValInt("MouseClickX");
            _mouseClickY = GetInIValInt("MouseClickY");

            tcpIpHelper = new PlcTcpIpHelper(serviceIp, port);

            if (GetInIValInt("IsMouseWatcher") > 0)
            {
                mouseWatcher = eventHookFactory.GetMouseWatcher();
                mouseWatcher.OnMouseInput += (s, e) =>
                {
                    var mouseEvent = (MouseEventArgs)e.EventArgs;
                    switch (e.KeyMouseEventType)
                    {
                        //case MacroEventType.MouseClick:
                        case MacroEventType.MouseDown:
                            //case MacroEventType.MouseUp:
                            if (mouseEvent.Button == MouseButtons.Middle)
                            {
                                ShowMsg("鼠标光标坐标：" + string.Format("x={0:0000}; y={1:0000}", mouseEvent.X, mouseEvent.Y));
                            }

                            break;
                        default:
                            break;
                    }
                };
            }
        }


        private void FormMain_Load(object sender, EventArgs e)
        {
            if (GetInIValInt("IsMouseWatcher") > 0)
            {
                mouseWatcher.Start(Hook.GlobalEvents());
            }

            isStart = false;
            txtIp.Text = serviceIp;
            txtPort.Text = port.ToString();

            timer1.Start();

            lblWriteFile.Text = WriteFilePath;

            if (IsFocusInput && string.IsNullOrWhiteSpace(_activateProcessesName))
            {
                MessageBox.Show("未设置焦点输入程序名称，请进行设置再运行！！！", "提示", MessageBoxButtons.OK);
            }

            if (IsAutoRun)
            {
                ShowMsg($"{DateTime.Now:HH:mm:ss} 自动连接....");
                Thread.Sleep(2000);
                StartRun();
            }
        }

        private void btnClientReceive_Click(object sender, EventArgs e)
        {
            StartRun();
        }


        void StartRun()
        {
            LogHelper.Info("连接启动");

            if (txtIp.Text.Trim() != serviceIp || txtPort.Text.Trim() != port.ToString())
            {
                IniFile.WriteIni(SECTIONKEY, "ServiceIp", txtIp.Text.Trim(), paramFile);
                IniFile.WriteIni(SECTIONKEY, "ServicePort", txtPort.Text.Trim(), paramFile);

                serviceIp = txtIp.Text.Trim();
                int.TryParse(txtPort.Text.Trim(), out port);
            }
            ShowMsg($"{DateTime.Now:HH:mm:ss} 等待连接启动中 {ThreadSleep} ms");
            Thread.Sleep(ThreadSleep);

            if (isDebug)
            {
                for (int i = 0; i < 20; i++)
                {
                    ParseKeyCode($"788508-{i.ToString("000")}");
                    Thread.Sleep(1000);
                }

                return;
            }

            if (isStart == false)
            {
                ShowMsg($"{DateTime.Now:HH:mm:ss} 开始连接 {txtIp.Text.Trim()}:{txtPort.Text.Trim()}");
                Connect();
            }
            else
            {
                DisconnectTcpIp();
            }

        }


        /// <summary>
        /// 激活进程窗体，显示在最前（或启动进程）
        /// </summary>
        void ActivationSwitchWindow()
        {
            if (IsSpecifyFocusProcess == false) return;

            /*使用Process.Start方法启动程序。
               使用ShowWindow方法设置窗口的状态为最大化。
               使用SetForegroundWindow方法将窗口设置为最前端。*/

            //要启动的进程名称，可以在任务管理器里查看，一般是不带.exe后缀的;
            Process[] temp = Process.GetProcessesByName(_activateProcessesName);//在所有已启动的进程中查找需要的进程；
            if (temp.Length > 0)//如果查找到
            {
                IntPtr handle = temp[0].MainWindowHandle;

                SetTargetProgram(handle);
            }
            else if (IsStartProcesses && !string.IsNullOrWhiteSpace(_startProcessesName))
            {
                //Process.Start(_activateProcessesName + ".exe");//否则启动进程
                // 启动外部程序
                Process process = new Process();
                process.StartInfo.FileName = _startProcessesName; // 要启动的程序路径+程序.exe
                process.Start();

                // 等待程序启动
                process.WaitForInputIdle();

                IntPtr handle = process.MainWindowHandle;

                SetTargetProgram(handle);
            }
            else
            {
                ShowMsg($"{DateTime.Now:HH:mm:ss} 焦点输入接收程序未启动，请进行启动！");

                LogHelper.Error("焦点输入未找到要激活接收数据的程序：" + _activateProcessesName);
            }
        }

        void SetTargetProgram(IntPtr handle)
        {
            // 获取当前最前的窗口句柄
            IntPtr foregroundWindowHandle = GetForegroundWindow();

            // 判断当前进程窗口是否是最前 
            if (handle != foregroundWindowHandle)
            {
                SwitchToThisWindow(handle, true); // 激活，显示在最前
            }

            // 将窗口最大化
            ShowWindow(handle, SW_SHOWMAXIMIZED); // SW_MAXIMIZE


            if (_mouseClickX > 0 && _mouseClickY > 0)
            {
                // 将鼠标光标移动到指定位置
                SetCursorPos(_mouseClickX, _mouseClickY);

                // 模拟鼠标左键按下和抬起
                mouse_event(MOUSEEVENTF_LEFTDOWN, _mouseClickX, _mouseClickY, 0, 0);
                mouse_event(MOUSEEVENTF_LEFTUP, _mouseClickX, _mouseClickY, 0, 0);

            }

        }

        /// <summary>
        /// 焦点输入，或生成对应文件
        /// </summary>
        /// <param name="keyCode"></param>
        void ParseKeyCode(string keyCode)
        {
            if (string.IsNullOrWhiteSpace(keyCode.Trim()))
            {
                ShowMsg($"{DateTime.Now:HH:mm:ss} 条码为空不执行操作");
                return;
            }

            string fileName = $"{WriteFilePath}\\{keyCode}.nc";
            try
            {
                lblWriteFile.Text = WriteFilePath;
                //优先写NC文件，再进行焦点输入
                if (isWirteFile)
                {
                    File.WriteAllText(fileName, "");
                    LogHelper.Info($"文件 {fileName} 生成完成");
                    ShowMsg($"{DateTime.Now:HH:mm:ss} 文件 {fileName} 生成完成");
                }
                if (IsFocusInput)
                {
                    ActivationSwitchWindow();

                    Thread.Sleep(200);
                    sim.Keyboard.KeyPress(VirtualKeyCode.BACK); // 园方直接删除

                    Thread.Sleep(200);

                    sim.Keyboard
                      .ModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.VK_A)  // 园方不支持    Ctrl+A 全选                  
                      .TextEntry(keyCode).Sleep(TextEntrySleep)
                      .KeyPress(VirtualKeyCode.RETURN);

                    LogHelper.Info($"焦点输入 {keyCode} 完成");
                    ShowMsg($"{DateTime.Now:HH:mm:ss} 焦点输入 {keyCode} 完成");
                }

            }
            catch (Exception e)
            {
                ShowMsg($"{DateTime.Now:HH:mm:ss} {(isWirteFile ? "生成文件" : "焦点输入")} {keyCode} 失败 {e.Message}");
                LogHelper.Error($"焦点输入失败  keyCode:{keyCode}  fileName:{fileName}  isWirteFile:{isWirteFile}  IsFocusInput：{IsFocusInput}", e);
            }

        }

        #region  数据处理
        /// <summary>
        /// 连接扫码枪
        /// </summary>
        public void Connect()
        {
            try
            {
                ScanCameraTcpInit();

                if (scanCameraClient.Connected == false)
                {
                    ShowMsg($"{DateTime.Now:HH:mm:ss} 连接失败");
                }
                else
                {
                    btnClientReceive.Text = "处理中";
                    btnClientReceive.ForeColor = Color.White;
                    btnClientReceive.BackColor = Color.Green;
                    isStart = true;
                    ShowMsg($"{DateTime.Now:HH:mm:ss} 连接成功");
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error($"连接失败", ex);
                ShowMsg($"{DateTime.Now:HH:mm:ss} 连接失败: " + ex.Message);
            }
        }

        /// <summary>
        /// 断开扫码枪
        /// </summary>
        public void DisconnectTcpIp()
        {
            try
            {
                if (scanCameraClient != null)
                {
                    scanCameraClient.Dispose();
                    Thread.Sleep(200);
                    scanCameraClient = null;

                }
                isStart = false;

                btnClientReceive.Text = "开 始";
                btnClientReceive.ForeColor = Color.Black;
                btnClientReceive.BackColor = SystemColors.Control;
                ShowMsg("断开连接-D");
            }
            catch (Exception ex)
            {
                //showMsg("断开连接-D"+ex.Message);
                LogHelper.Error($"断开连接-DE", ex);
            }
        }


        /// <summary>
        /// 连接扫描枪通信
        /// </summary>
        public void ScanCameraTcpInit()
        {
            try
            {
                scanCameraClient = new AsyncTcpClient(IPAddress.Parse(serviceIp), port);
                scanCameraClient.Encoding = Encoding.UTF8;
                scanCameraClient.ServerExceptionOccurred += ScanCameraClient_ServerExceptionOccurred;
                scanCameraClient.ServerConnected += ScanCameraClient_ServerConnected;
                scanCameraClient.ServerDisconnected += ScanCameraClient_ServerDisconnected;
                scanCameraClient.PlaintextReceived += ScanCameraClient_PlaintextReceived4;
                scanCameraClient.Connect();
                Thread.Sleep(millisecondsTimeout: 100);
                if (scanCameraClient.Connected == false)
                {
                    //addOtherHistoryOnBord("连接扫描枪通信失败");
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error($"连接通信失败", ex);
                //LogHelper.Exception(ex);

                //showMsg($"连接扫描枪通信失败-{ex.Message}");
            }
        }
        /// <summary>
        /// 服务异常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScanCameraClient_ServerExceptionOccurred(object sender, TcpServerExceptionOccurredEventArgs e)
        {
            LogHelper.Error($"服务异常-ScanCameraClient_ServerExceptionOccurred-{serviceIp}:{port}--{e.Exception.Message}", e.Exception);
            // showMsg("服务异常");
        }
        /// <summary>
        /// 连接成功
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScanCameraClient_ServerConnected(object sender, TcpServerConnectedEventArgs e)
        {
            LogHelper.Error($"连接成功-ScanCameraClient_ServerConnected-{serviceIp}:{port}-");
            //showMsg("连接成功");
        }
        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScanCameraClient_ServerDisconnected(object sender, TcpServerDisconnectedEventArgs e)
        {
            LogHelper.Error($"断开连接-ScanCameraClient_ServerDisconnected-{serviceIp}:{port}--{e.ToString()}");
            //showMsg("断开连接-SD");
        }
        /// <summary>
        /// 接收到的明文
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScanCameraClient_PlaintextReceived4(object sender, TcpDatagramReceivedEventArgs<string> e)
        {
            string data;
            try
            {
                if (e.Datagram == null)
                {
                    return;
                }
                if (e.Datagram.Trim() == "")
                {
                    return;
                }
                data = e.Datagram.TrimEnd("\r\n".ToCharArray());
                string log = $"接收到 {data}";
                StringBuilder result = new StringBuilder();
                byte[] dataBy = Encoding.UTF8.GetBytes(data);
                foreach (byte val in dataBy)
                {
                    if (val > 33) //ASCII 33之前的值在此无用 32为空格 space
                    {
                        result.Append((char)val);
                    }
                }
                data = result.ToString();
                LogHelper.Info($"{log} 过滤无效字符后：{data}");

                ShowMsg($"{DateTime.Now:HH:mm:ss} 接收到 {data}");
                ParseKeyCode(data);
            }
            catch (Exception ex)
            {
                LogHelper.Error($"接收失败", ex);
                ShowMsg($"接收失败{ex}");
            }
        }


        #endregion

        void ShowMsg(string msg)
        {
            if (TotalItemCount > ShowItemCount)
            {
                string text = textBoxLog.Text;
                int indexOfFirstNewLine = text.IndexOf('\n');
                if (indexOfFirstNewLine >= 0)
                {
                    // 删除第一行，包括换行符
                    text = text.Substring(indexOfFirstNewLine + 1);
                    textBoxLog.Text = text;
                }
            }

            textBoxLog.AppendText(msg + "\r\n");
            textBoxLog.ScrollToCaret();

            TotalItemCount++;
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                if (eventHookFactory != null)
                    eventHookFactory.Dispose();

                sim.Disable(MacroEventType.MouseClick);
            }
            catch (Exception ex)
            {

            }
        }

        string GetInIValStr(string key)
        {
            return IniFile.ReadIni(SECTIONKEY, key, paramFile);
        }

        int GetInIValInt(string key, int defaultVal = 0)
        {
            int r = 0;
            string str = IniFile.ReadIni(SECTIONKEY, key, paramFile);
            int.TryParse(str, out r);

            if (r == 0)
            {
                return defaultVal;
            }

            return r;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            //启动中，进行检测通信是否断开，如断开则进行重连
            if (isStart == true)
            {
                if (scanCameraClient == null)
                {
                    LogHelper.Error("重新 ScanCameraTcpInit");
                    ScanCameraTcpInit();
                }
                Thread.Sleep(200);

                if (scanCameraClient.Connected == false)
                {
                    scanCameraClient.Connect();
                    LogHelper.Error("重新连接");
                }
            }
            //int plcCheckStauts = GetInIValInt("plcCheckStauts", 0);
            //PLC心跳
            //if (plcCheckStauts < 1 && tcpIpHelper.PlcChecketStatus(plcCheckStauts) == false)
            //{
            //    LogHelper.Error("PLC心跳检测失败，与PLC通信失败");
            //}

        }

        private void btnWriteCode_Click(object sender, EventArgs e)
        {
            //ActivationSwitchWindow();
            //return;
            Thread.Sleep(1000);
            //if (!string.IsNullOrWhiteSpace(txtBarCode.Text))
            {
                ParseKeyCode(txtBarCode.Text.Trim());
                txtBarCode.Text = "";
            }
        }

        private void NotifyIcon_Click(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                Show(); // 恢复窗体
                this.WindowState = FormWindowState.Normal; // 将窗体设置为正常状态
                notifyIcon.Visible = false; // 隐藏托盘图标
            }
        }


        private void FormMain_SizeChanged(object sender, EventArgs e)
        {
            // 初始化托盘图标
            if (IsMinToNotifyIcon > 0)
            {
                if (this.WindowState == FormWindowState.Minimized)
                {
                    Hide(); // 最小化时隐藏窗体
                    notifyIcon.Visible = true; // 显示托盘图标
                }
            }
        }

        private void txtBarCode_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (!string.IsNullOrWhiteSpace(txtBarCode.Text))
                {
                    ParseKeyCode(txtBarCode.Text.Trim());
                    txtBarCode.Text = "";
                }
            }
        }

        /// <summary>
        /// 获取DLL的构建时间
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>        
        DateTime RetrieveLinkerTimestamp(string filePath)
        {
            const int peHeaderOffset = 60;
            const int linkerTimestampOffset = 8;

            byte[] b = new byte[2048];

            try
            {
                using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    file.Read(b, 0, 2048);
                }
            }
            catch (Exception)
            {
                throw;
            }

            int i = BitConverter.ToInt32(b, peHeaderOffset);
            int secondsSince1970 = BitConverter.ToInt32(b, i + linkerTimestampOffset);
            DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            dt = dt.AddSeconds(secondsSince1970);
            dt = dt.ToLocalTime();
            return dt;
        }

        string GetLibraryVersion(string dllPath)
        {
            // 假设你的DLL名为"MyLibrary.dll"
            //string dllPath = "MyLibrary.dll";

            // 加载DLL
            Assembly myAssembly = Assembly.LoadFrom(dllPath);

            // 获取DLL版本
            Version version = myAssembly.GetName().Version;

            // 获取DLL构建时间
            DateTime buildTime = RetrieveLinkerTimestamp(dllPath);

            Console.WriteLine($"Version: {version}");
            Console.WriteLine($"Build Time: {buildTime}");

            return version.ToString();

        }

        private void FormMain_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            { 
                Point point = new Point(e.X, e.Y);
                contextMenuStrip1.Show(this, point);
            }
        }

        private void 隐藏条码手动输入ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            pnlTest.Visible = !pnlTest.Visible;
        }

        private void textBoxLog_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            { 
                Point point = new Point(e.X, e.Y);
                contextMenuStrip1.Show(this, point);
            }
        }
    }

    public class VersionInfo
    {
        public string Version { get; private set; }
        public DateTime BuildTime { get; private set; }

        public VersionInfo()
        {
            // 获取程序集的版本信息
            var assembly = Assembly.GetExecutingAssembly();
            Version = assembly.GetName().Version.ToString();

            // 获取构建时间，这里假设使用了 MSBuild 的预处理器定义
            //string buildTimeStr = assembly.GetCustomAttribute<AssemblyBuildTimeAttribute>().BuildTime;
            //BuildTime = DateTime.Parse(buildTimeStr);
        }
    }

    // 在代码中定义特性来读取构建时间
    public class AssemblyBuildTimeAttribute : Attribute
    {
        public readonly string BuildTime;

        public AssemblyBuildTimeAttribute(string buildTime)
        {
            BuildTime = buildTime;
        }
    }


    /*
     
     // 在构建脚本中定义预处理器定义，例如在 .csproj 文件中添加以下内容
<!-- MSBuild 中设置预处理器定义 -->
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
    <DefineConstants>AssemblyBuildTime=$(BuildTime)</DefineConstants>
</PropertyGroup>

     */
}
